//////////////////////////////////////////////
//                                          //
//          Alexander K. Haley's            //
//            Space Warz Game               //
//    (For Prototype Hardware, w/o CPU)     //
//                                          //
//                Build #3                  //
//           Last edit 5/3/2020             //
//        Originally made 5/3/2020          //
//                                          //
//        (c) Alexander K. Haley            //
//                  of                      //
//            Kincaid Arcade                //
//                                          //
//////////////////////////////////////////////
//Get it? Cinematronics Space Wars, Vectorbeam Space War, now Kincaid Arcade Space Warz. :)
//It seems we are running out of ways of differentiating between "Space War"s without changing "Space War".

//One thing I would certainly change if I did this again would be to rearrange pins to facilitate port manipulation.
//Also use a DUE.
//Because why not?

//Added #s 0-9
//Added flame particle animation
//Added screen optimization!!!

//address pins: a0-a10 = pin 22-32
//data pins: q0-q11 = pin 38-39
//misc pins:
//  processorready = pin 32
//  processoroverride = pin 7
//  writeenable = pin 34
//  outputenable = pin 35
//  chipselect = pin 36
//  framecomplete = pin 37  INPUT
//LED debugging pins:
//  ledone = pin 12
//  ledtwo = pin 11
//  ledthree = pin 10
//  errorled = pin 9

byte azero  = 22;
byte aone   = 23;
byte atwo   = 24;
byte athree = 25;
byte afour  = 26;
byte afive  = 27;
byte asix   = 28;
byte aseven = 29;
byte aeight = 30;
byte anine  = 31;
byte aten   = 32;

//data pins
byte qzero     = 38;
byte qone      = 39;
byte qtwo      = 40;
byte qthree    = 41;
byte qfour     = 42;
byte qfive     = 43;
byte qsix      = 44;
byte qseven    = 45;
byte qeight    = 46;
byte qnine     = 47;
byte qten      = 48;
byte qeleven   = 49;
//byte qtwelve   = 50; Technically, they aren't ever used...
//byte qthirteen = 51;
//byte qfourteen = 52;
//byte qfifteen  = 53;

//switch input pins
byte ptwofire   = A0; 
byte ptwothrust = A1;
byte ptwohyperspace = A2;
byte ptworight  = A3;
byte ptwoleft   = A4;

byte startbutton = A8;

byte ponefire   = A9;
byte ponethrust = A10;
byte ponehyperspace = A11; 
byte poneright  = A12;
byte poneleft   = A13;


//misc. pins
byte processorready = 33;

byte writeenable    = 34;
byte outputenable   = 35;
byte chipselect     = 36;
byte framecomplete  = 37;

byte processoroverride = 7;

byte ledone = 12;
byte ledtwo = 11;
byte ledthree = 10;
byte errorled = 9;

//Frame Buffer
int xcoords[600];
int ycoords[600];
int zvalues[600];


//variables
int currentaddress  = 1;
int internaladdress = 0;
int mathaddress     = 0;

int transferaddress = 0;

int currentdata = 0;
int mathdata    = 0;

byte bank = 0;
byte portdata = 0;

byte frame = 0; //used for indicating whether or not a processoroverride is necessary.

byte lastswitchstates[12];
byte currentswitchstates[12];
byte hitswitches[12];

//timing
unsigned long lastmillis = 0;
unsigned long currentmillis = 0;

//positions & other variables
//p1 ship
int alienxpos = 128;
int alienypos = 512;

float alienrotation = 0.0; //radians
int   aliendx = 0;
int   aliendy = 0;

float alienvelocity = 0.0;

int randomalienx = 0;
int randomalieny = 0;

byte alienflame = 0;

byte alienlocation = 56; //set it to a screen location that doesn't exist, so we can check and see if it was changed.

//p2 ship
int rocketxpos = 896;
int rocketypos = 512;

float rocketrotation = 3.142; //Also in radians
int   rocketdx = 0;
int   rocketdy = 0;

float rocketvelocity = 0.0;

int randomrocketx = 0;
int randomrockety = 0;

byte rocketflame = 0;

byte rocketlocation = 56; //set it to a screen location that doesn't exist, so we can check and see if it was changed.

//score, time digits, and associated variables.
//player one score (alien)
int ponescoreonex = 200; //tens
int ponescoreoney = 746;
byte ponetens = 0; //value of the digit

int ponescoretwox = 264; //ones
int ponescoretwoy = 746;
byte poneones = 0;

byte ponescore = 0;

//time digit positions
int timeonex = 376; //10 minutes
int timeoney = 746;
byte timetenminutes = 0;

int timetwox = 440; //1 minute
int timetwoy = 746;
byte timeminutes = 0;

int timethreex = 536; //10 seconds
int timethreey = 746;
byte timetenseconds = 0;

int timefourx = 600; //1 second
int timefoury = 746;
byte timeseconds = 0;

int gametime = 0; //in seconds

//player 2 score (rocket)
int ptwoscoreonex = 712; //tens
int ptwoscoreoney = 746;
byte ptwotens = 0;

int ptwoscoretwox = 776; //ones
int ptwoscoretwoy = 746;
byte ptwoones = 0;

byte ptwoscore = 0;


/////////////////////////////////////////////////
//                                             //
//                                             //
//      Screen Drawing Optimization Stuff      //
//                                             //
//                                             //
/////////////////////////////////////////////////
//each "location" on the screen is a box of 128 by 128 screen units. There are 6 vertical, and 8 horizontal boxes.
//Order of boxes on screen is as follows:
//   0     1     2     3     4     5     6     7
//   15    14    13    12    11    10    9     8
//   16    17    18    19    20    21    22    23
//   31    30    29    28    27    26    25    24
//   32    33    34    35    36    37    38    39
//   47    46    45    44    43    42    41    40

//a 1-d array is easier to manipulate than a 2-d array for this.
byte screenlocation[48];

byte location = 0; //current location within the screen matrix thingy.
int upperxbound = 0;
int upperybound = 0;

//An item is counted to be in a box by it's centerpoint, and not it's extremeties. (For stationary objects, the "center" is actually the bottom left. I.E. the Star, and digits)
//Stationary objects are just programmed into the box. Why waste time during the loop if the position never changes?
//Objects that move (ships, bullets, etc.) are assigned to a box with a for loop. 
//When it comes time to draw the objects, it compares to see if the box it was put in matches the current box.

//It is imperfect, but it is better than nothing. The real question is whether or not more boxes would take longer to optimize than the benefits gained... 
//                                                This method shines when there's loads of objects on the screen, like in Asteroids.


/////////////////////////////////////////////////
//                                             //
//                                             //
//               Game Variables                //
//                                             //
//                                             //
/////////////////////////////////////////////////

byte gameactive = 0;

/////////////////////////////////////////////////
//                                             //
//                                             //
//      Game Object Coordinates & Buffers      //
//                                             //
//                                             //
/////////////////////////////////////////////////

//star
int starx[9] = {0,  64, 56, 8,  32, 32, 8, 56};
int stary[9] = {32, 32, 8,  56, 64, 0,  8, 56};
int starz[9] = {0,  15, 0,  15, 0,  15, 0, 15};

int starxbuffer[9];
int starybuffer[9];
int starzbuffer[9];

byte starlocation = 28; //I didn't really have any other group of star stuff to put this.

//border
int borderx[6] = {0,   0,   1023, 1023,  0};
int bordery[6] = {128, 896, 896,  128,   128};
int borderz[6] = {0,   15,  15,   15,    15};

//p1 alien ship
float alienangle[19]    = {4.248, 4.390, 4.712, 1.951, 1.670, 2.035, 3.142, 4.712, 0.000, 1.107, 1.471, 1.190, 0.000, 5.034, 5.177, 4.248, 4.468, 4.712, 4.957}; //In radians :/
float aliendistance[19] = {26.8,  18.9,  18.0,  32.3,  30.1,  6.7,   6.0,   6.0,   6.0,   6.7,   30.1,  32.3,  18.0,  19.0,  26.8,  26.8,  24.7,  42.0,  24.7}; 
int   alienz[19]        = {0,     15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    0,     15,    15}; //the last two z values correspond to the thrust spray

float newalienangle[19] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

int alienxbuffer[19];
int alienybuffer[19];
int alienzbuffer[19];

//p2 rocket ship
float rocketangle[19]    = {4.391, 4.332, 3.927, 3.606, 2.677, 1.571, 0.464, 5.819, 5.498, 5.093, 5.034, 4.391, 4.712, 5.034, 0.000, 3.142, 2.035, 1.107, 0.000}; //Also in radians :/
float rocketdistance[19] = {19.0,  32.3,  25.5,  13.4,  13.4,  24.0,  13.4,  13.4,  25.5,  32.3,  19.0,  19.0,  42.0,  19.0,  3.0,   3.0,   6.7,   6.7,   3.0}; 
int   rocketz[19]        = {0,     15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    15,    0,     15,    15,    15,    15}; //0-indexed 12 & 13 correspond to thrust spray

float newrocketangle[19] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

int rocketxbuffer[19];
int rocketybuffer[19];
int rocketzbuffer[19];


////////////////////////
//                    //
//    Numbers 0-9     //
//                    //
////////////////////////

//each number is 48w x 80h

//0
int zeroxcoords[5] = {0, 0,  48, 48, 0};
int zeroycoords[5] = {0, 80, 80, 0,  0};
int zerozvalues[5] = {0, 15, 15, 15, 15};

//1
int onexcoords[2] = {48, 48};
int oneycoords[2] = {0,  80};
int onezvalues[2] = {0,  15};

//2
int twoxcoords[6] = {0,  48, 48, 0,  0,  48};
int twoycoords[6] = {80, 80, 40, 40, 0,  0};
int twozvalues[6] = {0,  15, 15, 15, 15, 15};

//3
int threexcoords[6] = {0, 48, 48, 0,  0,  48}; 
int threeycoords[6] = {0, 0,  80, 80, 40, 40};
int threezvalues[6] = {0, 15, 15, 15, 0,  15};

//4
int fourxcoords[5] = {0,  0,  48, 48, 48}; 
int fourycoords[5] = {80, 40, 40, 80, 0};
int fourzvalues[5] = {0,  15, 15, 0,  15};

//5
int fivexcoords[6] = {0, 48, 48, 0,  0,  48};
int fiveycoords[6] = {0, 0,  40, 40, 80, 80};
int fivezvalues[6] = {0, 15, 15, 15, 15, 15};

//6
int sixxcoords[5] = {0,  0,  48, 48, 0}; 
int sixycoords[5] = {80, 0,  0,  40, 40};
int sixzvalues[5] = {0,  15, 15, 15, 15};

//7
int sevenxcoords[3] = {0,  48, 0}; 
int sevenycoords[3] = {80, 80, 0};
int sevenzvalues[3] = {0,  15, 15};

//8
int eightxcoords[7] =  {0,  48, 48, 0,  0,  48, 48};
int eightycoords[7] =  {40, 40, 0,  0,  80, 80, 40};
int eightzvalues[7] =  {0,  15, 15, 15, 15, 15, 15};

//9
int ninexcoords[5] = {48, 48, 0,  0,  48};
int nineycoords[5] = {0,  80, 80, 40, 40};
int ninezvalues[5] = {0,  15, 15, 15, 15};

void setup() {
//Serial.begin(9600); //only needed for testing stuff

//The ports on the Mega are weird...
DDRA = DDRA | B11111111;
DDRB = DDRB | B01110000;
DDRC = DDRC | B11111110;
DDRD = DDRD | B10000000;
DDRG = DDRG | B00000111;
DDRH = DDRH | B01010000;
DDRL = DDRL | B11111111;

pinMode(ponefire,INPUT);
pinMode(ponethrust,INPUT);
pinMode(ponehyperspace,INPUT);
pinMode(poneright,INPUT);
pinMode(poneleft,INPUT);

pinMode(startbutton,INPUT);

pinMode(ptwofire,INPUT);
pinMode(ptwothrust,INPUT);
pinMode(ptwohyperspace,INPUT);
pinMode(ptworight,INPUT);
pinMode(ptwoleft,INPUT);

digitalWrite(chipselect,LOW);
digitalWrite(outputenable,HIGH); //Make sure we're in high impedance mode.
digitalWrite(writeenable,HIGH);

randomSeed(analogRead(15));
}

void loop() {
lastmillis = millis(); //Remember when the frame was begun, so we can know if it took too long. If too short, the program will stall until the frame has taken 16ms. (Throttling fps to ~60 max.) 

//read all of the switches.
readswitches();

//apply game logic
dogamelogic();

//manipulate game object xy -- basically all the transformations to do to the objects before drawing them to the screen.
manipulateobjectxy();

//optimize drawing order based on screen "zone" and write to buffer.
optimizedraworder();

//write stuff to the master buffer
writetomasterbuffer();

//load all of the x, y, and z values to the buffer.
writeobjectstoram();

//Check time to complete to millis watchdog - Light LED if too slow, and toggle active framebuffer.
vgenchecker();
}

////////////////////////////////////////////////
//                                            //
//                                            //
//       This section deals with all          //
//    of the x & y object transformations     //
//                                            //
//                                            //
////////////////////////////////////////////////

void manipulateobjectxy()
{
  manipulatestarxy();
  manipulaterocketshipxy();
  manipulatealienxy();
}

void manipulatestarxy()
{
  //width of star 64 by 64  
  //offsets star to the center of the screen.
  for(int i=0; i<9; i++)
    {
      starxbuffer[i] = starx[i] + 480;
      starybuffer[i] = stary[i] + 480;
      starzbuffer[i] = starz[i];  
    }
}

void manipulaterocketshipxy()
{
  for(int i=0; i<19; i++) //Change all thetas to match rotation
    {
      newrocketangle[i] = rocketangle[i]-1.571+rocketrotation; //the -1.571 is to compensate for the ship images being pointed at 90 degrees
    }

  for(int i=0; i<19; i++)
    {
      rocketxbuffer[i] = rocketdistance[i]*cos(newrocketangle[i]); 
      rocketybuffer[i] = rocketdistance[i]*sin(newrocketangle[i]); 
      rocketzbuffer[i] = rocketz[i]; 
    }

  for(int i=0; i<19; i++) //Shift the position of everything
    {
      rocketxbuffer[i] += rocketxpos;
      rocketybuffer[i] += rocketypos;
    }

  //the flame particle "animation"
  if(currentswitchstates[1] == 1)
    {
      if(rocketflame == 1)
        {
          rocketflame = 0;
        }
      else if(rocketflame == 0)
        {
          rocketzbuffer[12] = 0;
          rocketzbuffer[13] = 0;
          
          rocketflame = 1;  
        }
    }
}

void manipulatealienxy()
{
  for(int i=0; i<19; i++) //Change all thetas to match rotation
    {
      newalienangle[i] = alienangle[i]-1.571+alienrotation; //the -1.571 is to compensate for the ship images being pointed at 90 degrees
    }

  for(int i=0; i<19; i++)
    {
      alienxbuffer[i] = aliendistance[i]*cos(newalienangle[i]); 
      alienybuffer[i] = aliendistance[i]*sin(newalienangle[i]); 
      alienzbuffer[i] = alienz[i]; 
    }

  for(int i=0; i<19; i++) //Shift the position of everything
    {
      alienxbuffer[i] += alienxpos;
      alienybuffer[i] += alienypos;
    }

  //the flame particle "animation"
  if(currentswitchstates[7] == 1)
    {
      if(alienflame == 1)
        {
          alienflame = 0;
        }
      else if(alienflame == 0)
        {
          alienzbuffer[17] = 0;
          alienzbuffer[18] = 0;
          
          alienflame = 1;  
        }
    }
}

void manipulatedigit(int xoffset, int yoffset, byte digit)
{
  switch(digit)
    {
      case 0:
      break;
      case 1:
      break;
      case 2:
      break;
      case 3:
      break;
      case 4:
      break;
      case 5:
      break;
      case 6:
      break;
      case 7:
      break;
      case 8:
      break;
      case 9:
      break;  
    }
}

////////////////////////////////////////////////
//                                            //
//                                            //
//       This section deals with the          //
//                game logic                  //
//                                            //
//                                            //
////////////////////////////////////////////////

void dogamelogic()
{
  //outside of game


  //both
  if(hitswitches[5] == 1) //Start
    {
      if(gameactive == 0)
        {
          gameactive = 1;  
        }
      
      if(gameactive == 1)
        {
          gametime += 60; //add 60s to game time.
        }

      if(gametime <= 0)
        {
          gameactive = 0;
        }
    }

  //figure out what the score digits and time should be
  calculatescoretimenumbers();

  //during game
  
  //p2 rocket pos & rot stuff
  if(currentswitchstates[1] == 1) //P2 thrust  
    {
      rocketvelocity += 4.0; //gonna have to figure out better thrust stuff  
    }
  else if(currentswitchstates[1] == 0 && rocketvelocity > 0.0)
    {
      rocketflame = 0; //turn off the thrust particles
      rocketvelocity -= 1.0;  
    }
 
  if(rocketvelocity > 4.0) //don't let it move more than 240 pixels per second (1/4) screen
    {
      rocketvelocity = 4.0;  
    }

  if(currentswitchstates[3] == 1) //P2 Right
    {
      rocketrotation -= 0.07; //I hate radians
    }
  if(currentswitchstates[4] == 1) //P2 Left
    {
      rocketrotation += 0.07; //Normal people would say "4 degrees"
    }

  //make sure the rocket is always at a known angle.
  if(rocketrotation > 6.283)
    {
      rocketrotation = 0;
    }
  if(rocketrotation < 0)
    {
      rocketrotation = 6.283;  
    }

  //calculate directional movement based on angle and velocity;
  rocketdx = rocketvelocity*cos(rocketrotation);
  rocketdy = rocketvelocity*sin(rocketrotation);

  //move the ship
  rocketxpos += rocketdx;
  rocketypos += rocketdy;

  //make sure it's center isn't too close to the edge of the screen. If it is, have it wrap around.
  if(rocketxpos < 50)
    {
      rocketxpos = 973;  
    }
  if(rocketxpos > 973)
    {
      rocketxpos = 50;  
    }
  if(rocketypos < 178)
    {
      rocketypos = 846;  
    }
  if(rocketypos > 846)
    {
      rocketypos = 178;
    }

  //Hyperspace!
  if(hitswitches[2] == 1) //P2 Hyperspace
    {
       randomrocketx = random(50, 974);
       randomrockety = random(178, 846);

       rocketxpos = randomrocketx;
       rocketypos = randomrockety;
    }
  
  
  //p1 alien pos & rot stuff
  if(currentswitchstates[7] == 1) //P1 thrust  
    {
      alienvelocity += 4.0; //gonna have to figure out better thrust stuff  
    }
  else if(currentswitchstates[7] == 0 && alienvelocity > 0.0)
    {
      alienflame = 0; //turn off the thrust particles
      alienvelocity -= 1.0;  
    }
 
  if(alienvelocity > 4.0) //don't let it move more than 240 pixels per second (1/4) screen
    {
      alienvelocity = 4.0;  
    }

  if(currentswitchstates[9] == 1) //P2 Right
    {
      alienrotation -= 0.07; //I hate radians
    }
  if(currentswitchstates[10] == 1) //P2 Left
    {
      alienrotation += 0.07; //Normal people would say "4 degrees"
    }

  //make sure the rocket is always at a known angle.
  if(alienrotation > 6.283)
    {
      alienrotation = 0;
    }
  if(alienrotation < 0)
    {
      alienrotation = 6.283;  
    }

  //calculate directional movement based on angle and velocity;
  aliendx = alienvelocity*cos(alienrotation);
  aliendy = alienvelocity*sin(alienrotation);

  //move the ship
  alienxpos += aliendx;
  alienypos += aliendy;

  //make sure it's center isn't too close to the edge of the screen. If it is, have it wrap around.
  if(alienxpos < 50)
    {
      alienxpos = 973;  
    }
  if(alienxpos > 973)
    {
      alienxpos = 50;  
    }
  if(alienypos < 178)
    {
      alienypos = 846;  
    }
  if(alienypos > 846)
    {
      alienypos = 178;
    }

  //Hyperspace!
  if(hitswitches[8] == 1) //P1 Hyperspace
    {
       randomalienx = random(50, 974);
       randomalieny = random(178, 846);

       alienxpos = randomalienx;
       alienypos = randomalieny;
    }

  
}

void calculatescoretimenumbers()
{
  //time
  timetenminutes = 0;
  timeminutes = 0;
  timetenseconds = 0;
  timeseconds = 0;
  
  while(gametime >= 600)
    {
      gametime -= 600;
      timetenminutes += 1;  
    }
  while(gametime >= 60)
    {
      gametime -= 60;
      timeminutes += 1;  
    }
  while(gametime >= 10)
    {
      gametime -= 10;
      timetenseconds += 1;  
    }
  while(gametime >= 1)
    {
      gametime -= 1;
      timeseconds += 1;  
    }
}



////////////////////////////////////////////////
//                                            //
//          This section deals with           //
//   optimizing the order which items are     //
//    drawn on the screen, to reduce the      //
//     time spent drawing invisible lines     //
//                                            //
////////////////////////////////////////////////
void optimizedraworder()
{
  //clear the old data of screen locations with stuff in them.
  for(int i=0; i<48; i++)
    {
      screenlocation[i] = 0;  
    }

  //clear screen locations of all moving objects. (Ship, bullets, etc.)
    rocketlocation = 56;
    alienlocation = 56;
    
  //load unchanging screen locations. (Locations with stuff that doesn't move, like the star.)
    screenlocation[28] = 1; //Star

// Digits haven't been implemented yet.
//    screenlocation[14] = 1; //All these are where the score digits are.
//    screenlocation[13] = 1;
//    screenlocation[12] = 1;
//    screenlocation[11] = 1;
//    screenlocation[10] = 1;
//    screenlocation[9]  = 1;

  //go through and assign a screen location to each object's position.
  upperybound = 256;

  for(int i=0; i<6; i++) //counts from bottom to top
    {
      if(i == 0 || i == 2 || i == 4)
        {
          //line counts right to left
          upperxbound = 128;
          for(int m=0; m<8; m++)
            {
              location = 47-(i*8)-m;
              
              //all that fancy if stuff to see if object belongs in this location.
                //player 1 ship
                if(alienlocation == 56 && alienxpos < upperxbound && alienypos < upperybound) //check if location currently unset; and x and y values within bounds of location that is being compared against.
                  {
                    alienlocation = location;  
                    screenlocation[location] = 1;
                  }
                //player 2 ship
                if(rocketlocation == 56 && rocketxpos < upperxbound && rocketypos < upperybound) //check if location currently unset; and x and y values within bounds of location that is being compared against.
                  {
                    rocketlocation = location;
                    screenlocation[location] = 1;  
                  }

              
              upperxbound += 128;
            }
        }
      else if(i == 1 || i == 3 || i == 5)
        {
          //line counts from left to right
          upperxbound = 128;
          for(int n=0; n<8; n++)
            {
              location = 40-(i*8)+n;
              
              //all that fancy if stuff to see if object belongs in this location.
                //player 1 ship
                if(alienlocation == 56 && alienxpos < upperxbound && alienypos < upperybound) //check if location currently unset; and x and y values within bounds of location that is being compared against.
                  {
                    alienlocation = location;  
                    screenlocation[location] = 1;
                  }
                //player 2 ship
                if(rocketlocation == 56 && rocketxpos < upperxbound && rocketypos < upperybound) //check if location currently unset; and x and y values within bounds of location that is being compared against.
                  {
                    rocketlocation = location; 
                    screenlocation[location] = 1; 
                  }
              
              upperxbound += 128;
            }
        }
      upperybound += 128;
    }


}

////////////////////////////////////////////////
//                                            //
//          This section deals with           //
//   moving the buffered coordinates to the   //
//      master buffer, so it can then be      //
//          written to the RAM chips.         //
//                                            //
////////////////////////////////////////////////
void writetomasterbuffer()
{
  transferaddress = 0;
  
  //load the border around the screen
  //not necessary for now.
//  for(int i=0; i<6; i++)
//   {
//     xcoords[transferaddress] = borderx[i];
//     ycoords[transferaddress] = bordery[i];
//     zvalues[transferaddress] = borderz[i];
//     transferaddress++;  
//   }

  //cycle through all the screen locations.
  for(int x=0; x<48; x++)
    {
        if(screenlocation[x] == 1)
          {
            //load the star
            if(starlocation == x)
              {
                for(int i=0; i<9; i++)
                  {
                    xcoords[transferaddress] = starxbuffer[i];
                    ycoords[transferaddress] = starybuffer[i];
                    zvalues[transferaddress] = starzbuffer[i];
                    transferaddress++;  
                  }
              }
            //load the p1 alien vessel
            if(alienlocation == x)
              {
                for(int i=0; i<19; i++)
                  {
                    xcoords[transferaddress] = alienxbuffer[i];  
                    ycoords[transferaddress] = alienybuffer[i]; 
                    zvalues[transferaddress] = alienzbuffer[i]; 
                    transferaddress++;
                  }
              }
            //load the p2 rocket ship
            if(rocketlocation == x)
              {
                for(int i=0; i<19; i++)
                  {
                    xcoords[transferaddress] = rocketxbuffer[i];  
                    ycoords[transferaddress] = rocketybuffer[i]; 
                    zvalues[transferaddress] = rocketzbuffer[i]; 
                    transferaddress++;
                  }
              }
          }
    }

  //then, at the end, have a coorinate with a Z value of 128 to signal the end of the frame.
  xcoords[transferaddress] = xcoords[transferaddress-1];
  ycoords[transferaddress] = ycoords[transferaddress-1];
  zvalues[transferaddress] = 128;
}

////////////////////////////////////////////////
//                                            //
//                                            //
//       Miscellanneous control stuff         //
//                                            //
//                                            //
////////////////////////////////////////////////

void vgenchecker()
{
  if(frame == 0)
    {
      initiateprocessoroverride();  
      frame = 1;
      return;
    }
  while(digitalRead(framecomplete) == LOW)
    {
      delayMicroseconds(1);  
      
      //save this for implementing the watchdog.
      /*currentmillis = millis();
      if(currentmillis > lastmillis + 16)
        {
            
        }*/ 
    }
  if(digitalRead(framecomplete) == HIGH)
    {
      currentmillis = millis();
      //The throttle is disabled since the frame doesn't take close to the 16ms, which causes the sample&hold issues.
      /*while(currentmillis < lastmillis + 16) //this should throttle it down to ~60 fps tops. 
        {
          delayMicroseconds(1);
          currentmillis = millis(); //otherwise it gets stuck in this loop.
        }*/
   
      //digitalWrite(processorready,HIGH);
      PORTC = PORTC | B00010000;
      //digitalWrite(processorready,LOW);
      PORTC = PORTC & B11101111;
    }  
}

void readswitches()
{
  currentswitchstates[0] = digitalRead(ptwofire);
  currentswitchstates[1] = digitalRead(ptwothrust);
  currentswitchstates[2] = digitalRead(ptwohyperspace);
  currentswitchstates[3] = digitalRead(ptworight);
  currentswitchstates[4] = digitalRead(ptwoleft);

  currentswitchstates[5] = digitalRead(startbutton);
  
  currentswitchstates[6] = digitalRead(ponefire);
  currentswitchstates[7] = digitalRead(ponethrust);
  currentswitchstates[8] = digitalRead(ponehyperspace);
  currentswitchstates[9] = digitalRead(poneright);
  currentswitchstates[10] = digitalRead(poneleft);

  for(byte x=0; x<11; x++)
    {
      if(currentswitchstates[x] == 1 && lastswitchstates[x] == 0)
        {
          hitswitches[x] = 1;
        }
      else
        {
          hitswitches[x] = 0;  
        }
    }

  for(byte x=0; x<11; x++)
    {
      lastswitchstates[x] = currentswitchstates[x];  
    }
/*
  if(hitswitches[0] == 1) //P2 Fire button
    {
      Serial.println("P2 fired");  
    }
  if(hitswitches[1] == 1) //P2 Thrust
    {
      Serial.println("P2 applied thrust");  
    }
  if(hitswitches[2] == 1) //P2 Hyperspace
    {
      Serial.println("P2 entered hyperspace");  
    }
  if(hitswitches[3] == 1) //P2 Right
    {
      Serial.println("P2 turned right");  
    }
  if(hitswitches[4] == 1) //P2 Left
    {
      Serial.println("P2 turned left");  
    }
  if(hitswitches[5] == 1) //Start
    {
      Serial.println("The start button was pressed.");  
    }
  if(hitswitches[6] == 1) //P1 Fire
    {
      Serial.println("P1 Fired");  
    }
  if(hitswitches[7] == 1) //P1 Thrust
    {
      Serial.println("P1 applied thrust");  
    }
  if(hitswitches[8] == 1) //P1 Hyperspace
    {
      Serial.println("P1 hyperspaced");  
    }
  if(hitswitches[9] == 1) //P1 Right
    {
      Serial.println("P1 turned right");  
    }
  if(hitswitches[10] == 1) //P1 Left
    {
      Serial.println("P1 turned left");  
    }
*/
}

///////////////////////////////////////////
//                                       //
//       This section deals with         //
//         handling all the RAM          //
//          writing and stuff            //
//                                       //
///////////////////////////////////////////

void writeobjectstoram()
{
  while(zvalues[internaladdress] != 128)
    {
      computeaddress();
      computedata();
      writedata();
      currentaddress++;
    }
  currentaddress = 1;
  internaladdress = 0;
  bank = 0;
}

void computeaddress()
{
  //split address into zeros and ones
  mathaddress = currentaddress;
  
  if(mathaddress >= 1024)
    {
      //digitalWrite(aten,HIGH); 
      PORTC = PORTC | B00100000;
      mathaddress -= 1024; 
    }
  else
    {
      //digitalWrite(aten,LOW);
      PORTC = PORTC & B11011111;
    }
    
  if(mathaddress >= 512)
    {
      //digitalWrite(anine,HIGH); 
      PORTC = PORTC | B01000000; 
      mathaddress -= 512; 
    }
  else
    {
      //digitalWrite(anine,LOW);
      PORTC = PORTC & B10111111;
    }
    
  if(mathaddress >= 256)
    {
      //digitalWrite(aeight,HIGH);  
      PORTC = PORTC | B10000000;
      mathaddress -= 256; 
    }
  else
    {
      //digitalWrite(aeight,LOW);
      PORTC = PORTC & B01111111; 
    }

  portdata = mathaddress;
  PORTA = portdata;
}

void computedata()
{
  if(bank == 3)
    {
      bank = 0;  
      internaladdress ++;
    }
  
  if(bank == 0) //x bank
    {
      currentdata = xcoords[internaladdress];
    }
  else if(bank == 1) //y bank
    {
      currentdata = ycoords[internaladdress];
    }
  else if(bank == 2) //zbank
    {
      currentdata = zvalues[internaladdress];
    }

  mathdata = currentdata;

  if(mathdata >= 2048)
    {
      //digitalWrite(qeleven,HIGH); 
      PORTL = PORTL | B00000001;
      mathdata -= 2048; 
    }
  else
    {
      //digitalWrite(qeleven,LOW);
      PORTL = PORTL & B11111110;
    }

  if(mathdata >= 1024)
    {
      //digitalWrite(qten,HIGH); 
      PORTL = PORTL | B00000010;
      mathdata -= 1024; 
    }
  else
    {
      //digitalWrite(qten,LOW);
      PORTL = PORTL & B11111101;
    }
    
  if(mathdata >= 512)
    {
      //digitalWrite(qnine,HIGH);
      PORTL = PORTL | B00000100;  
      mathdata -= 512; 
    }
  else
    {
      //digitalWrite(qnine,LOW);
      PORTL = PORTL & B11111011;
    }
    
  if(mathdata >= 256)
    {
      //digitalWrite(qeight,HIGH);  
      PORTL = PORTL | B00001000;
      mathdata -= 256; 
    }
  else
    {
      //digitalWrite(qeight,LOW);
      PORTL = PORTL & B11110111;
    }
    
  if(mathdata >= 128)
    {
      //digitalWrite(qseven,HIGH);  
      PORTL = PORTL | B00010000;
      mathdata -= 128; 
    }
  else
    {
      //digitalWrite(qseven,LOW);
      PORTL = PORTL & B11101111;
    }
    
  if(mathdata >= 64)
    {
      //digitalWrite(qsix,HIGH);  
      PORTL = PORTL | B00100000;
      mathdata -= 64; 
    }
  else
    {
      //digitalWrite(qsix,LOW);
      PORTL = PORTL & B11011111;
    }
    
  if(mathdata >= 32)
    {
      //digitalWrite(qfive,HIGH); 
      PORTL = PORTL | B01000000; 
      mathdata -= 32; 
    }
  else
    {
      //digitalWrite(qfive,LOW);
      PORTL = PORTL & B10111111;
    }
    
  if(mathdata >= 16)
    {
      //digitalWrite(qfour,HIGH);  
      PORTL = PORTL | B10000000;
      mathdata -= 16; 
    }
  else
    {
      //digitalWrite(qfour,LOW);
      PORTL = PORTL & B01111111;
    }
    
  if(mathdata >= 8)
    {
      //digitalWrite(qthree,HIGH);  
      PORTG = PORTG | B00000001;
      mathdata -= 8; 
    }
  else
    {
      //digitalWrite(qthree,LOW);
      PORTG = PORTG & B11111110;
    }
    
  if(mathdata >= 4)
    {
      //digitalWrite(qtwo,HIGH); 
      PORTG = PORTG | B00000010; 
      mathdata -= 4; 
    }
  else
    {
      //digitalWrite(qtwo,LOW);
      PORTG = PORTG & B11111101;
    }
    
  if(mathdata >= 2)
    {
      //digitalWrite(qone,HIGH);  
      PORTG = PORTG | B00000100;
      mathdata -= 2; 
    }
  else
    {
      //digitalWrite(qone,LOW);
      PORTG = PORTG & B11111011;
    }
    
  if(mathdata >= 1)
    {
      //digitalWrite(qzero,HIGH);  
      PORTD = PORTD | B10000000;
      mathdata -= 1; 
    }
  else
    {
      //digitalWrite(qzero,LOW);
      PORTD = PORTD & B01111111;
    }

  if(mathdata != 0)
    {
      //digitalWrite(errorled,HIGH);  
    }
}

void writedata()
{
  //digitalWrite(writeenable,LOW);
  //digitalWrite(writeenable,HIGH);
  PORTC = PORTC & B11110111; //why does this work? Well, each port manipulation takes 4.9 us, which is 4900 nanoseconds.
  PORTC = PORTC | B00001000; //That may seem like a long time, but if you consider that each digitalWrite takes up to 2 milliseconds...
  bank ++;
}

void initiateprocessoroverride()
{
  //digitalWrite(processoroverride, HIGH);
  PORTH = PORTH | B00010000;
  //digitalWrite(processorready, HIGH);
  PORTC = PORTC | B00010000;
  //digitalWrite(processoroverride, LOW);
  PORTH = PORTH & B11101111;
  //digitalWrite(processorready, LOW);  
  PORTC = PORTC & B11101111;
}
